[Chapter Five][Previous]
[Art of Assembly][Randall
Hyde]
Art of Assembly: Chapter Five
- 5.7 - Sample Programs
- 5.7.1 - Simple Variable Declarations
- 5.7.2 - Using Pointer Variables
- 5.7.3 - Single Dimension Array Access
- 5.7.4 - Multidimensional Array Access
- 5.7.5 - Simple Structure Access
- 5.7.6 - Arrays of Structures
- 5.7.7 - Structures and Arrays as Fields
of Another Structure
- 5.7.8 - Pointers to Structures and Arrays
of Structures
5.7 Sample Programs
The following short sample programs demonstrate many of the concepts
appearing in this chapter.
5.7.1 Simple Variable Declarations
; Sample variable declarations
; This sample file demonstrates how to declare and access some simple
; variables in an assembly language program.
;
; Randall Hyde
;
;
; Note: global variable declarations should go in the "dseg" segment:
dseg segment para public 'data'
; Some simple variable declarations:
character byte ? ;"?" means uninitialized.
UnsignedIntVar word ?
DblUnsignedVar dword ?
;You can use the typedef statement to declare more meaningful type names:
integer typedef sword
char typedef byte
FarPtr typedef dword
; Sample variable declarations using the above types:
J integer ?
c1 char ?
PtrVar FarPtr ?
; You can tell MASM & DOS to initialize a variable when DOS loads the
; program into memory by specifying the initial value in the operand
; field of the variable's declaration:
K integer 4
c2 char 'A'
PtrVar2 FarPtr L ;Initializes PtrVar2 with the
; address of L.
; You can also set aside more than one byte, word, or double word of
; storage using these directives. If you place several values in the
; operand field, separated by commas, the assembler will emit one byte,
; word, or dword for each operand:
L integer 0, 1, 2, 3
c3 char 'A', 0dh, 0ah, 0
PtrTbl FarPtr J, K, L
; The BYTE directive lets you specify a string of characters byte enclosing
; the string in quotes or apostrophes. The directive emits one byte of data
; for every character in the string (not including the quotes or apostrophes
; that delimit the string):
string byte "Hello world",0dh,0ah,0
dseg ends
; The following program demonstrates how to access each of the above
; variables.
cseg segment para public 'code'
assume cs:cseg, ds:dseg
Main proc
mov ax, dseg ;These statements are provided by
mov ds, ax ; shell.asm to initialize the
mov es, ax ; segment register.
; Some simple instructions that demonstrate how to access memory:
lea bx, L ;Point bx at first word in L.
mov ax, [bx] ;Fetch word at L.
add ax, 2[bx] ;Add in word at L+2 (the "1").
add ax, 4[bx] ;Add in word at L+4 (the "2").
add ax, 6[bx] ;Add in word at L+6 (the "3").
mul K ;Compute (0+1+2+3)*123.
mov J, ax ;Save away result in J.
les bx, PtrVar2 ;Loads es:di with address of L.
mov di, K ;Loads 4 into di
mov ax, es:[bx][di] ;Fetch value of L+4.
; Examples of some byte accesses:
mov c1, ' ' ;Put a space into the c1 var.
mov al, c2 ;c3 := c2
mov c3, al
Quit: mov ah, 4ch ;Magic number for DOS
int 21h ; to tell this program to quit.
Main endp
cseg ends
sseg segment para stack 'stack'
stk byte 1024 dup ("stack ")
sseg ends
zzzzzzseg segment para public 'zzzzzz'
LastBytes byte 16 dup (?)
zzzzzzseg ends
end Main
5.7.2 Using Pointer Variables
; Using Pointer Variables in an Assembly Language Program
;
; This short sample program demonstrates the use of pointers in
; an assembly language program.
;
; Randall Hyde
dseg segment para public 'data'
; Some variables we will access indirectly (using pointers):
J word 0, 0, 0, 0
K word 1, 2, 3, 4
L word 5, 6, 7, 8
; Near pointers are 16-bits wide and hold an offset into the current data
; segment (dseg in this program). Far pointers are 32-bits wide and hold
; a complete segment:offset address. The following type definitions let
; us easily create near and far pointers
nWrdPtr typedef near ptr word
fWrdPtr typedef far ptr word
; Now for the actual pointer variables:
Ptr1 nWrdPtr ?
Ptr2 nWrdPtr K ;Initialize with K's address.
Ptr3 fWrdPtr L ;Initialize with L's segmented adrs.
dseg ends
cseg segment para public 'code'
assume cs:cseg, ds:dseg
Main proc
mov ax, dseg ;These statements are provided by
mov ds, ax ; shell.asm to initialize the
mov es, ax ; segment register.
; Initialize Ptr1 (a near pointer) with the address of the J variable.
lea ax, J
mov Ptr1, ax
; Add the four words in variables J, K, and L together using pointers to
; these variables:
mov bx, Ptr1 ;Get near ptr to J's 1st word.
mov si, Ptr2 ;Get near ptr to K's 1st word.
les di, Ptr3 ;Get far ptr to L's 1st word.
mov ax, ds:[si] ;Get data at K+0.
add ax, es:[di] ;Add in data at L+0.
mov ds:[bx], ax ;Store result to J+0.
add bx, 2 ;Move to J+2.
add si, 2 ;Move to K+2.
add di, 2 ;Move to L+2.
mov ax, ds:[si] ;Get data at K+2.
add ax, es:[di] ;Add in data at L+2.
mov ds:[bx], ax ;Store result to J+2.
add bx, 2 ;Move to J+4.
add si, 2 ;Move to K+4.
add di, 2 ;Move to L+4.
mov ax, ds:[si] ;Get data at K+4.
add ax, es:[di] ;Add in data at L+4.
mov ds:[bx], ax ;Store result to J+4.
add bx, 2 ;Move to J+6.
add si, 2 ;Move to K+6.
add di, 2 ;Move to L+6.
mov ax, ds:[si] ;Get data at K+6.
add ax, es:[di] ;Add in data at L+6.
mov ds:[bx], ax ;Store result to J+6.
Quit: mov ah, 4ch ;Magic number for DOS
int 21h ; to tell this program to quit.
Main endp
cseg ends
sseg segment para stack 'stack'
stk byte 1024 dup ("stack ")
sseg ends
zzzzzzseg segment para public 'zzzzzz'
LastBytes byte 16 dup (?)
zzzzzzseg ends
end Main
5.7.3 Single Dimension Array Access
; Sample variable declarations
; This sample file demonstrates how to declare and access some single
; dimension array variables in an assembly language program.
;
; Randall Hyde
.386 ;Need to use some 80386
option segment:use16 ; addressing modes.
dseg segment para public 'data'
J word ?
K word ?
L word ?
M word ?
JD dword 0
KD dword 1
LD dword 2
MD dword 3
; Some simple uninitialized array declarations:
ByteAry byte 4 dup (?)
WordAry word 4 dup (?)
DwordAry dword 4 dup (?)
RealAry real8 4 dup (?)
; Some arrays with initialized values:
BArray byte 0, 1, 2, 3
WArray word 0, 1, 2, 3
DWArray dword 0, 1, 2, 3
RArray real8 0.0, 1.0, 2.0, 3.0
; An array of pointers:
PtrArray dword ByteAry, WordAry, DwordAry, RealAry
dseg ends
; The following program demonstrates how to access each of the above
; variables.
cseg segment para public 'code'
assume cs:cseg, ds:dseg
Main proc
mov ax, dseg ;These statements are provided by
mov ds, ax ; shell.asm to initialize the
mov es, ax ; segment register.
; Initialize the index variables. Note that these variables provide
; logical indices into the arrays. Don't forget that we've got to
; multiply these values by the element size when accessing elements of
; an array.
mov J, 0
mov K, 1
mov L, 2
mov M, 3
; The following code shows how to access elements of the arrays using
; simple 80x86 addressing modes:
mov bx, J ;AL := ByteAry[J]
mov al, ByteAry[bx]
mov bx, K ;AX := WordAry[K]
add bx, bx ;Index*2 since this is a word array.
mov ax, WordAry[bx]
mov bx, L ;EAX := DwordAry[L]
add bx, bx ;Index*4 since this is a double
add bx, bx ; word array.
mov eax, DwordAry[bx]
mov bx, M ;BX := address(RealAry[M])
add bx, bx ;Index*8 since this is a quad
add bx, bx ; word array.
add bx, bx
lea bx, RealAry[bx] ;Base address + index*8.
; If you have an 80386 or later CPU, you can use the 386's scaled indexed
; addressing modes to simplify array access.
mov ebx, JD
mov al, ByteAry[ebx]
mov ebx, KD
mov ax, WordAry[ebx*2]
mov ebx, LD
mov eax, DwordAry[ebx*4]
mov ebx, MD
lea bx, RealAry[ebx*8]
Quit: mov ah, 4ch ;Magic number for DOS
int 21h ; to tell this program to quit.
Main endp
cseg ends
sseg segment para stack 'stack'
stk byte 1024 dup ("stack ")
sseg ends
zzzzzzseg segment para public 'zzzzzz'
LastBytes byte 16 dup (?)
zzzzzzseg ends
end Main
5.7.4 Multidimensional Array Access
; Multidimensional Array declaration and access
;
; Randall Hyde
.386 ;Need these two statements to
option segment:use16 ; use the 80386 register set.
dseg segment para public 'data'
; Indices we will use for the arrays.
J word 1
K word 2
L word 3
; Some two-dimensional arrays.
; Note how this code uses the "dup" operator to suggest the size
; of each dimension.
B2Ary byte 3 dup (4 dup (?))
W2Ary word 4 dup (3 dup (?))
D2Ary dword 2 dup (6 dup (?))
; 2D arrays with initialization.
; Note the use of data layout to suggest the sizes of each array.
B2Ary2 byte 0, 1, 2, 3
byte 4, 5, 6, 7
byte 8, 9, 10, 11
W2Ary2 word 0, 1, 2
word 3, 4, 5
word 6, 7, 8
word 9, 10, 11
D2Ary2 dword 0, 1, 2, 3, 4, 5
dword 6, 7, 8, 9, 10, 11
; A sample three dimensional array.
W3Ary word 2 dup (3 dup (4 dup (?)))
dseg ends
cseg segment para public 'code'
assume cs:cseg, ds:dseg
Main proc
mov ax, dseg ;These statements are provided by
mov ds, ax ; shell.asm to initialize the
mov es, ax ; segment register.
; AL := B2Ary2[j,k]
mov bx, J ;index := (j*4+k)
add bx, bx ;j*2
add bx, bx ;j*4
add bx, K ;j*4+k
mov al, B2Ary2[bx]
; AX := W2Ary2[j,k]
mov ax, J ;index := (j*3 + k)*2
mov bx, 3
mul bx ;(j*3)-- This destroys DX!
add ax, k ;(j*3+k)
add ax, ax ;(j*3+k)*2
mov bx, ax
mov ax, W2Ary2[bx]
; EAX := D2Ary[i,j]
mov ax, J ;index := (j*6 + k)*4
mov bx, 6
mul bx ;DX:AX := j*6, ignore overflow in DX.
add ax, k ;j*6 + k
add ax, ax ;(j*6 + k)*2
add ax, ax ;(j*6 + k)*4
mov bx, ax
mov eax, D2Ary[bx]
; Sample access of a three dimensional array.
;
; AX := W3Ary[J,K,L]
mov ax, J ;index := ((j*3 + k)*4 + l)*2
mov bx, 3
mul bx ;j*3
add ax, K ;j*3 + k
add ax, ax ;(j*3 + k)*2
add ax, ax ;(j*3 + k)*4
add ax, l ;(j*3 + k)*4 + l
add ax, ax ;((j*3 + k)*4 + l)*2
mov bx, ax
mov ax, W3Ary[bx]
Quit: mov ah, 4ch ;Magic number for DOS
int 21h ; to tell this program to quit.
Main endp
cseg ends
sseg segment para stack 'stack'
stk byte 1024 dup ("stack ")
sseg ends
zzzzzzseg segment para public 'zzzzzz'
LastBytes byte 16 dup (?)
zzzzzzseg ends
end Main
5.7.5 Simple Structure Access
; Sample Structure Definitions and Accesses.
;
; Randall Hyde
dseg segment para public 'data'
; The following structure holds the bit values for an 80x86 mod-reg-r/m byte.
mode struct
modbits byte ?
reg byte ?
rm byte ?
mode ends
Instr1Adrs mode {} ;All fields uninitialized.
Instr2Adrs mode {}
; Some structures with initialized fields.
axbx mode {11b, 000b, 000b} ;"ax, ax" adrs mode.
axdisp mode {00b, 000b, 110b} ;"ax, disp" adrs mode.
cxdispbxsi mode {01b, 001b, 000b} ;"cx, disp8[bx][si]" mode.
; Near pointers to some structures:
sPtr1 word axdisp
sPtr2 word Instr2Adrs
dseg ends
cseg segment para public 'code'
assume cs:cseg, ds:dseg
Main proc
mov ax, dseg ;These statements are provided by
mov ds, ax ; shell.asm to initialize the
mov es, ax ; segment register.
; To access fields of a structure variable directly, just use the "."
; operator like you would in Pascal or C:
mov al, axbx.modbits
mov Instr1Adrs.modbits, al
mov al, axbx.reg
mov Instr1Adrs.reg, al
mov al, axbx.rm
mov Instr1Adrs.rm, al
; When accessing elements of a structure indirectly (that is, using a
; pointer) you must specify the structure type name as the first
; "field" so MASM doesn't get confused:
mov si, sPtr1
mov di, sPtr2
mov al, ds:[si].mode.modbits
mov ds:[di].mode.modbits, al
mov al, ds:[si].mode.reg
mov ds:[di].mode.reg, al
mov al, ds:[si].mode.rm
mov ds:[di].mode.rm, al
Quit: mov ah, 4ch ;Magic number for DOS
int 21h ; to tell this program to quit.
Main endp
cseg ends
sseg segment para stack 'stack'
stk byte 1024 dup ("stack ")
sseg ends
zzzzzzseg segment para public 'zzzzzz'
LastBytes byte 16 dup (?)
zzzzzzseg ends
end Main
5.7.6 Arrays of Structures
; Arrays of Structures
;
; Randall Hyde
dseg segment para public 'data'
; A structure that defines an (x,y) coordinate.
; Note that the Point data type requires four bytes.
Point struct
X word ?
Y word ?
Point ends
; An uninitialized point:
Pt1 Point {}
; An initialized point:
Pt2 Point {12,45}
; A one-dimensional array of uninitialized points:
PtAry1 Point 16 dup ({}) ;Note the "{}" inside the parens.
; A one-dimensional array of points, all initialized to the origin.
PtAry1i Point 16 dup ({0,0})
; A two-dimensional array of points:
PtAry2 Point 4 dup (4 dup ({}))
; A three-dimensional array of points, all initialized to the origin.
PtAry3 Point 2 dup (3 dup (4 dup ({0,0})))
; A one-dimensional array of points, all initialized to different values:
iPtAry Point {0,0}, {1,2}, {3,4}, {5,6}
; Some indices for the arrays:
J word 1
K word 2
L word 3
dseg ends
; The following program demonstrates how to access each of the above
; variables.
cseg segment para public 'code'
assume cs:cseg, ds:dseg
Main proc
mov ax, dseg ;These statements are provided by
mov ds, ax ; shell.asm to initialize the
mov es, ax ; segment register.
; PtAry1[J] := iPtAry[J]
mov bx, J ;Index := J*4 since there are four
add bx, bx ; bytes per array element (each
add bx, bx ; element contains two words).
mov ax, iPtAry[bx].X
mov PtAry1[bx].X, ax
mov ax, iPtAry[bx].Y
mov PtAry1[bx].Y, ax
; CX := PtAry2[K,L].X; DX := PtAry2[K,L].Y
mov bx, K ;Index := (K*4 + J)*4
add bx, bx ;K*2
add bx, bx ;K*4
add bx, J ;K*4 + J
add bx, bx ;(K*4 + J)*2
add bx, bx ;(K*4 + J)*4
mov cx, PtAry2[bx].X
mov dx, PtAry2[bx].Y
; PtAry3[j,k,l].X := 0
mov ax, j ;Index := ((j*3 +k)*4 + l)*4
mov bx, 3
mul bx ;j*3
add ax, k ;j*3 + k
add ax, ax ;(j*3 + k)*2
add ax, ax ;(j*3 + k)*4
add ax, l ;(j*3 + k)*4 + l
add ax, ax ;((j*3 + k)*4 + l)*2
add ax, ax ;((j*3 + k)*4 + l)*4
mov bx, ax
mov PtAry3[bx].X, 0
Quit: mov ah, 4ch ;Magic number for DOS
int 21h ; to tell this program to quit.
Main endp
cseg ends
sseg segment para stack 'stack'
stk byte 1024 dup ("stack ")
sseg ends
zzzzzzseg segment para public 'zzzzzz'
LastBytes byte 16 dup (?)
zzzzzzseg ends
end Main
5.7.7 Structures and Arrays as Fields of Another Structure
; Structures Containing Structures as fields
; Structures Containing Arrays as fields
;
; Randall Hyde
dseg segment para public 'data'
Point struct
X word ?
Y word ?
Point ends
; We can define a rectangle with only two points.
; The color field contains an eight-bit color value.
; Note: the size of a Rect is 9 bytes.
Rect struct
UpperLeft Point {}
LowerRight Point {}
Color byte ?
Rect ends
; Pentagons have five points, so use an array of points to
; define the pentagon. Of course, we also need the color
; field.
; Note: the size of a pentagon is 21 bytes.
Pent struct
Color byte ?
Pts Point 5 dup ({})
Pent ends
; Okay, here are some variable declarations:
Rect1 Rect {}
Rect2 Rect {{0,0}, {1,1}, 1}
Pentagon1 Pent {}
Pentagons Pent {}, {}, {}, {}
Index word 2
dseg ends
cseg segment para public 'code'
assume cs:cseg, ds:dseg
Main proc
mov ax, dseg ;These statements are provided by
mov ds, ax ; shell.asm to initialize the
mov es, ax ; segment register.
; Rect1.UpperLeft.X := Rect2.UpperLeft.X
mov ax, Rect2.Upperleft.X
mov Rect1.Upperleft.X, ax
; Pentagon1 := Pentagons[Index]
mov ax, Index ;Need Index*21
mov bx, 21
mul bx
mov bx, ax
; Copy the first point:
mov ax, Pentagons[bx].Pts[0].X
mov Pentagon1.Pts[0].X, ax
mov ax, Pentagons[bx].Pts[0].Y
mov Pentagon1.Pts[0].Y, ax
; Copy the second point:
mov ax, Pentagons[bx].Pts[2].X
mov Pentagon1.Pts[4].X, ax
mov ax, Pentagons[bx].Pts[2].Y
mov Pentagon1.Pts[4].Y, ax
; Copy the third point:
mov ax, Pentagons[bx].Pts[4].X
mov Pentagon1.Pts[8].X, ax
mov ax, Pentagons[bx].Pts[4].Y
mov Pentagon1.Pts[8].Y, ax
; Copy the fourth point:
mov ax, Pentagons[bx].Pts[6].X
mov Pentagon1.Pts[12].X, ax
mov ax, Pentagons[bx].Pts[6].Y
mov Pentagon1.Pts[12].Y, ax
; Copy the fifth point:
mov ax, Pentagons[bx].Pts[8].X
mov Pentagon1.Pts[16].X, ax
mov ax, Pentagons[bx].Pts[8].Y
mov Pentagon1.Pts[16].Y, ax
; Copy the Color:
mov al, Pentagons[bx].Color
mov Pentagon1.Color, al
Quit: mov ah, 4ch ;Magic number for DOS
int 21h ; to tell this program to quit.
Main endp
cseg ends
sseg segment para stack 'stack'
stk byte 1024 dup ("stack ")
sseg ends
zzzzzzseg segment para public 'zzzzzz'
LastBytes byte 16 dup (?)
zzzzzzseg ends
end Main
5.7.8 Pointers to Structures and Arrays of Structures
; Pointers to structures
; Pointers to arrays of structures
;
; Randall Hyde
.386 ;Need these two statements so
option segment:use16 ; we can use 80386 registers
dseg segment para public 'data'
; Sample structure.
; Note: size is seven bytes.
Sample struct
b byte ?
w word ?
d dword ?
Sample ends
; Some variable declarations:
OneSample Sample {}
SampleAry Sample 16 dup ({})
; Pointers to the above
OnePtr word OneSample ;A near pointer.
AryPtr dword SampleAry
; Index into the array:
Index word 8
dseg ends
; The following program demonstrates how to access each of the above
; variables.
cseg segment para public 'code'
assume cs:cseg, ds:dseg
Main proc
mov ax, dseg ;These statements are provided by
mov ds, ax ; shell.asm to initialize the
mov es, ax ; segment register.
; AryPtr^[Index] := OnePtr^
mov si, OnePtr ;Get pointer to OneSample
les bx, AryPtr ;Get pointer to array of samples
mov ax, Index ;Need index*7
mov di, 7
mul di
mov di, ax
mov al, ds:[si].Sample.b
mov es:[bx][di].Sample.b, al
mov ax, ds:[si].Sample.w
mov es:[bx][di].Sample.w, ax
mov eax, ds:[si].Sample.d
mov es:[bx][di].Sample.d, eax
Quit: mov ah, 4ch ;Magic number for DOS
int 21h ; to tell this program to quit.
Main endp
cseg ends
sseg segment para stack 'stack'
stk byte 1024 dup ("stack ")
sseg ends
zzzzzzseg segment para public 'zzzzzz'
LastBytes byte 16 dup (?)
zzzzzzseg ends
end Main
- 5.7 - Sample Programs
- 5.7.1 - Simple Variable Declarations
- 5.7.2 - Using Pointer Variables
- 5.7.3 - Single Dimension Array Access
- 5.7.4 - Multidimensional Array Access
- 5.7.5 - Simple Structure Access
- 5.7.6 - Arrays of Structures
- 5.7.7 - Structures and Arrays as Fields
of Another Structure
- 5.7.8 - Pointers to Structures and Arrays
of Structures
Art of Assembly: Chapter Five - 26 SEP 1996
[Chapter Five][Previous]
[Art of Assembly][Randall
Hyde]